from durus.file_storage import FileStorage
from durus.connection import Connection
from durus import persistent_dict
from durus import persistent
import os, types

from core.base import ComponentBase, ParentChanged
from core import cmds

PersistentObject = persistent.PersistentObject
PersistentDict = persistent_dict.PersistentDict


ACCEPTED_TYPES = (int, float, long, str, types.NoneType)

class Package(object):
    def __init__(self, component):
        self.component = component
        self.content = PersistentDict()
        
    def __getstate__(self):
        state = {}
        state['__class_name__'] = self.component.__class__.__name__
        state['__name__'] = self.component.name
        base_dict = self.component.data_dict()
        base_dict['__custom_data__'] = self.component.__save__()
        self.validate_dict(base_dict, state)
        print 'SAVING STATE', state
        for name, value in state.items():
            self.content[name] = value
        return {'content':self.content}
    
    def __setsstate__(self, state):
        print 'SETSTATE'
        component_type = cmds.get_type(state['__class_name__'])
        instance = component_type(name=state['__name__'])
        self.component(instance)
        
        print 'LOADED COMPONENT', self.component
        
        self.component.__load__(state['__custom_data__'])
        
        print 'LOADING STATE', state
        
        for name, value in state.items():
            setattr(self.component, name, value)

    def validate_data(self, data):
        if isinstance(data, ACCEPTED_TYPES):
            return data
            new_dict[name] = data
        elif isinstance(data, dict):
            new_dict = {} 
            self.validate_dict(data, new_dict)
            return new_dict
        elif isinstance(data, ComponentBase):
            return Package(data)
        #elif isinstance(data, PersistentComponent):
        #    return data
        elif isinstance(data, list):
            new_list = []
            self.validate_list(data, new_list)
            return new_list
        else:
            print 'COULD NOT STORE DATA:', str(data)
        
    def validate_list(self, L, new_list):
        for item in L:
            new_list.append(self.validate_data(item))
        
    def validate_dict(self, base_dict, new_dict):
        for name, data in base_dict.items():
            new_dict[name] = self.validate_data(data)
            
    
        


class DurusDB(object):
    def __init__(self):
        self.path        = os.path.expanduser('~/testdb.fs')
        self.packages    = {}
        self.connected = False
        #self.connect()
        ParentChanged.connect(self.on_parent_change)
        
    def connect(self):
        if self.connected:
            return
        self.file_storage   = FileStorage(self.path)
        self.connection     = Connection(self.file_storage)
        self.root           = self.connection.get_root()
        self.connected = True
    
    def on_parent_change(self, node):
        if node.parent is None:
            self.add_root_node(node)
        else:
            self.rem_root_node(node)
    
    def _rename(self, instance, old_name, new_name):
        try:
            self.remove_instance(instance, old_name)
        except KeyError, e:
            pass
        instance._name = new_name
        self.add_instance(instance)
    
    def reload(self):
        self.file_storage.close()
        self.connect()
        
    def commit(self):
        self.connection.commit()
        
    def print_db(self):
        for name, value in self.root.items():
            print name, value
        
    def set_parent(self, inst, parent):
        pass
        
    def _create_group(self):
        group = PersistentDict()
        group['instance'] = inst
        group['children'] = PersistentDict()
        
    def add_root_node(self, node):
        print 'add root node', node
        space = '__root_nodes__'
        if not self.root.has_key(space):
            self.root[space] = PersistentDict()
        self.root[space][node.name] = node
    
    def rem_root_node(self, node):
        space = '__root_nodes__'
        if not self.root.has_key(space):
            self.root[space] = PersistentDict()
        if self.root[space].has_key(node.name):
            del self.root[space][node.name]
    
    def add_instance(self, inst):
        parent = inst.parent
        cls_name = inst.__class__.__name__
        if not self.root.has_key(cls_name):
            self.root[cls_name] = PersistentDict()
        self.root[cls_name][inst.name] = inst
        
        if parent is None:
            self.add_root_node(inst)
        
        self.commit()
    
    def remove_instance(self, inst, name):
        cls_name = inst.__class__.__name__
        del self.root[cls_name][name]
        if self.root['__root_nodes__'].has_key(name):
            del self.root['__root_nodes__'][name]
    
    def root_nodes(self):
        return self.root['__root_nodes__'].values()
    
    def parent_changed(self):
        pass
        
    def get(self, type_name, inst_name):
        inst_dict = self.root.get(type_name)
        if inst_dict is None:
            return None
        return inst_dict.get(inst_name)

    def all_instances(self):
        pass

    def instance_names(self, type_name):
        if isinstance(type_name, (types.ClassType, type,)):
            type_name = type_name.__name__
        inst_dict = self.root.get(type_name)
        if inst_dict is None:
            return []
        return inst_dict.keys()

    def instances(self, type_name):
        if isinstance(type_name, (types.ClassType, type,)):
            type_name = type_name.__name__
        inst_dict = self.root.get(type_name)
        if inst_dict is None:
            return []
        return inst_dict.values()
        
    def load_instance(self, name):
        pass
        
        